using System;
using System.Text.RegularExpressions;
using Fadd.Globalization;
#if TEST
using Xunit;
#endif

namespace Fadd.Validation
{
    /// <summary>
    /// Validates that a string property is an correct email.
    /// </summary>
    /// <para>
    /// Language file items:
    /// <list type="table">
    ///     <listheader>
    ///         <term>ItemName</term>
    ///         <description>Language text</description>
    ///     </listheader>
    ///     <item>
    ///         <term>Email</term>
    ///         <description>'{0}' must be a valid email address.</description>
    ///     </item>
    /// </list>
    /// </para>
    public class ValidateEmailAttribute : ValidateAttribute
    {
        private const string EmailRegEx = @"^[a-zA-Z0-9_\.\-]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z]{2,4}$";

        /// <summary>
        /// Localize the error.
        /// </summary>
        /// <param name="fieldName">Localized field name.</param>
        /// <param name="validationLanguage">Language node with all validation translations.</param>
        /// <returns>A localized error message if the validation failed; otherwise null.</returns>
        /// <example>
        /// <code>
        /// attribute.Localize("FirstName", "'{0}' is required"); 
        /// // will return "'{0}' is required" if the validation failed, else null.
        /// </code>
        /// </example>
        public override string Format(string fieldName, ILanguageNode validationLanguage)
        {
            return string.Format(validationLanguage["Email"], fieldName);
        }

        /// <summary>
        /// Determines if the validation support the specified type.
        /// </summary>
        /// <param name="type">Property/Value type.</param>
        /// <returns>true if type is supported.</returns>
        /// <remarks>
        /// Used when validation objects are generated.
        /// </remarks>
        public override bool SupportsType(Type type)
        {
            return type == typeof (string);
        }

        /// <summary>
        /// Validate value
        /// </summary>
        /// <param name="context">Can be used to send a context object to the validation class. Useful if you provide your own validation classes which need to get information from your application. <seealso cref="BeforeValidationEventArgs"/></param>
        /// <param name="value">value to validate</param>
        /// <returns>
        /// true if value passed the validation; otherwise false.
        /// </returns>
        /// <exception cref="NotSupportedException">Thrown if the object isn't a string</exception>
        public override bool Validate(object context, object value)
        {
			if(value == null)
				return true;

            if (value is string)
            {
                string email = (string) value;
				if(string.IsNullOrEmpty(email))
					return true;

                return Regex.IsMatch(email, EmailRegEx);
            }

            throw new NotSupportedException(value.GetType() + " is not supported.");
        }

#if TEST
        [Fact]
        private static void Test()
        {
            ValidateEmailAttribute attr = new ValidateEmailAttribute();
            Assert.True(attr.Validate(null, "something@somewhere.com"));
            Assert.True(attr.Validate(null, "a.b@c.d.ef"));
            Assert.True(attr.Validate(null, "0123@456.info"));
            Assert.False(attr.Validate(null, "something@somewhere.12"));
            Assert.False(attr.Validate(null, "a.%@c.d.ef"));
            Assert.False(attr.Validate(null, "0123@&.info"));
        }
#endif

    }
}